use std::fs::File;
use std::io::Read;
use std::collections::HashMap;
use lazy_static::lazy_static;
use std::sync::Mutex;

pub struct CfgInfo {
    pub ip: String,
    pub port: u16,
}

impl CfgInfo {
    pub fn parse_and_build(json_str: &str) -> Result<CfgInfo, Box<dyn std::error::Error>> 
    {
        let mut file = File::open(json_str)?;
        let mut contents = String::new();
        file.read_to_string(&mut contents)?;
        let mut ecu_map = ECU_MAP.lock().unwrap();

        let json: serde_json::Value = serde_json::from_str(&contents)?;
        let ip = json["ip"].as_str().unwrap().to_string();
        let port = json["port"].as_u64().unwrap() as u16;
        let ecus = json["ecus"].as_array().unwrap();
        for ecu in ecus {
            let name = ecu["name"].as_str().unwrap().to_string();
            let pn = ecu["pn"].as_str().unwrap().to_string();
            let sw = ecu["sw"].as_str().unwrap().to_string();
            let addr_str = ecu["addr"].as_str().unwrap();
            //去掉json中字段addr中的 0x 前缀，并转换为十六进制
            let addr_hex_val  = u16::from_str_radix(&addr_str[2..], 16).unwrap();
            println!("name: {}, pn: {}, sw: {}, addr: 0x{:02X}", name, pn, sw, addr_hex_val);
            let ecu_info = EcuInfo::new(name, pn, sw, addr_hex_val);
            ecu_map.add_ecu(ecu_info);
        }
        Ok(CfgInfo { 
            ip, 
            port, 
        })
    }

    pub fn _clone(&self) -> CfgInfo 
    {
        CfgInfo {
            ip: self.ip.clone(),
            port: self.port,
        }
    }
}

pub struct EcuInfo {
    pub _name: String,
    pub pn: String,
    pub sw: String,
    pub addr: u16,
}

impl EcuInfo {
    fn new(_name: String, pn: String, sw: String, addr: u16) -> EcuInfo 
    {
        EcuInfo {
            _name,
            pn,
            sw,
            addr,
        }
    }

    pub fn _get_name(&self) -> &str 
    {
        &self._name
    }

    pub fn get_pn(&self) -> &str 
    {
        &self.pn
    }

    pub fn get_sw(&self) -> &str 
    {
        &self.sw
    }
}

pub struct EcuMap {
    ecus: HashMap<u16, EcuInfo>,
}

impl EcuMap {
    fn new() -> EcuMap 
    {
        EcuMap {
            ecus: HashMap::new(),
        }
    }

    fn add_ecu(&mut self, ecu: EcuInfo) 
    {
        self.ecus.insert(ecu.addr, ecu);
    }

    pub fn get_ecu(&self, addr: u16) -> Option<&EcuInfo> 
    {
        //判断 addr 是否在 ECU_MAP 中
        if self.ecus.contains_key(&addr) {
            return self.ecus.get(&addr);
        } else {
            return None;
        }
    }

    pub fn get_ecumap(&self) -> &HashMap<u16, EcuInfo> 
    {
        return &self.ecus;
    }
}

//定义一个全局变量
lazy_static! {
    pub static ref ECU_MAP: Mutex<EcuMap> = Mutex::new(EcuMap::new());
}